//
//  DateUtils.m
//  DateView
//
//  Created by ladaka31 ladaka on 13. 5. 31..
//  Copyright (c) 2013년 ladaka Inc. All rights reserved.
//

#import "DateUtils.h"

@implementation DateUtils

- (id)init {
    self = [super init];
    if (self) {
        dateFormatter = [[NSDateFormatter alloc] init];        
        gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
        offsetComponents = [[NSDateComponents alloc] init];
    }
    
    return self;
}

/**
 파라미터 date객체로 부터 년도 값을 리턴한다.
 @param date 날짜 객체
 @return 년도
*/
- (int)getYearFromDate:(NSDate *)date {
    [dateFormatter setDateFormat:@"yyyy"];
	return [[dateFormatter stringFromDate:date] intValue];
}

/**
 파라미터 date객체로 부터 년도 월을 리턴한다.
 @param date 날짜 객체
 @return 월
*/
- (int)getMonthFromDate:(NSDate *)date {
    [dateFormatter setDateFormat:@"MM"];
	return [[dateFormatter stringFromDate:date] intValue];
}

/**
 파라미터 date객체로 부터 년도 시간을 리턴한다. 시간은 24시간 체계 임
 @param date 날짜 객체
 @return 시간
*/
- (int)getHourFromDate:(NSDate *)date {
    [dateFormatter setDateFormat:@"HH"];
    return [[dateFormatter stringFromDate:date] intValue];
}

/**
 파라미터 date객체로 부터 년도 분을 리턴한다.
 @param date 날짜 객체
 @return 분
 */
- (int)getMinuteFromDate:(NSDate *)date {
    [dateFormatter setDateFormat:@"mm"];
    return [[dateFormatter stringFromDate:date] intValue];
}

/**
 파라미터 date객체로 부터 날짜를 리턴한다.
 @param date 날짜 객체
 @return 날짜
 */
- (int)getDayFromDate:(NSDate *)date {
    [dateFormatter setDateFormat:@"dd"];
	return [[dateFormatter stringFromDate:date] intValue];
}

/**
 파라미터 date로부터 날짜를 파라미터 iday만큼 일자를 증가한다.
 @param date 날짜 객체
 @param iday 증가할 날 수
 @return iday만큼 일자가 증가된 NSDate객체 리턴
 */
- (NSDate *)incDay:(NSDate *)date increment:(int) iday {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:iday];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iMonth만큼 달을 증가한다.
 @param date 날짜 객체
 @param iMonth 증가할 달 수
 @return iMonth만큼 달이 증가된 NSDate객체 리턴
 */
- (NSDate *)incMonth:(NSDate *)date increment:(int)iMonth;  {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:iMonth];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];

    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iYear만큼 년도를 증가한다.
 @param date 날짜 객체
 @param iYear 증가할 년 수
 @return iYear만큼 년이 증가된 NSDate객체 리턴
 */
- (NSDate *)incYear:(NSDate *)date increment:(int)iYear {
    [offsetComponents setYear:iYear];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iWeek만큼 주를 증가한다.
 @param date 날짜 객체
 @param iWeek 증가할 주 수
 @return iWeek만큼 주가 증가된 NSDate객체 리턴
 */
- (NSDate *)incWeek:(NSDate *)date increment:(int)iWeek {
    int day = iWeek * 7;
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:day];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

- (NSDate *) inCustomDay:(NSDate *)date increment:(int)days index:(int)index {
    int day = days * index;
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:day];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iHour만큼 시간을 증가한다.
 @param date 날짜 객체
 @param iHour 증가할 시간 수
 @return iHour만큼 시간이 증가된 NSDate객체 리턴
 */
- (NSDate *)incHour:(NSDate *)date increment:(int)iHour {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:iHour];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iMinutes만큼 분을 증가한다.
 @param date 날짜 객체
 @param iMinutes 증가할 분 수
 @return iMinutes만큼 분이 증가된 NSDate객체 리턴
 */
- (NSDate *)incMinutes:(NSDate *)date increment:(int)iMinutes {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:iMinutes];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 second만큼 초를 증가한다.
 @param date 날짜 객체
 @param second 증가할 초
 @return second만큼 초가 증가된 NSDate객체 리턴
 */
- (NSDate *)incSecond:(NSDate *)date increment:(int)second {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:second];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iYear만큼 년도를 감소한다.
 @param date 날짜 객체
 @param iYear 감소할 년 수
 @return iYear만큼 년도가 감소된 NSDate객체 리턴
*/
- (NSDate *)decYear:(NSDate *)date decrement:(int)iYear {
    [offsetComponents setYear:-1*iYear];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];

    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iMonth만큼 월를 감소한다.
 @param date 날짜 객체
 @param iMonth 감소할 월 수
 @return iMonth만큼 월이 감소된 NSDate객체 리턴
 */
- (NSDate *)decMonth:(NSDate *)date decrement:(int)iMonth  {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:-1*iMonth];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];

    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iday만큼 일을 감소한다.
 @param date 날짜 객체
 @param iday 감소할 일 수
 @return iday만큼 일이 감소된 NSDate객체 리턴
 */
- (NSDate *)decDay:(NSDate *)date decrement:(int) iday {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:-1*iday];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];

    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iWeek만큼 주를 감소한다.
 @param date 날짜 객체
 @param iWeek 감소할 주 수
 @return iWeek만큼 주가 감소된 NSDate객체 리턴
 */
- (NSDate *)decWeek:(NSDate *)date decrement:(int)iWeek {
    int day = iWeek * 7;
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:-day];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];

    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iHour만큼 시간을 감소한다.
 @param date 날짜 객체
 @param iHour 감소할 시간 수
 @return iHour만큼 시간이 감소된 NSDate객체 리턴
 */
- (NSDate *)decHour:(NSDate *)date decrement:(int)iHour {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:-iHour];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 iMinutes만큼 분을 감소한다.
 @param date 날짜 객체
 @param iMinutes 감소할 분 수
 @return iMinutes만큼 분이 감소된 NSDate객체 리턴
 */
- (NSDate *)decMinutes:(NSDate *)date decrement:(int)iMinutes {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:-iMinutes];
    [offsetComponents setSecond:0];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 날짜를 파라미터 second만큼 초를 감소한다.
 @param date 날짜 객체
 @param second 감소할 초
 @return second만큼 초가 감소된 NSDate객체 리턴
*/
- (NSDate *)decSecond:(NSDate *)date decrement:(int)second {
    [offsetComponents setYear:0];
    [offsetComponents setMonth:0];
    [offsetComponents setDay:0];
    [offsetComponents setHour:0];
    [offsetComponents setMinute:0];
    [offsetComponents setSecond:-second];
    
    return [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
}

/**
 파라미터 date로부터 formatString에 맞는 날짜를 문자열로 리턴.\n
 자세한 날짜 포멧은 Apple API 참조
 @param formatString 날짜 포멧
 @param date 날짜 객체
 @return 날짜 문자열 리턴
*/
- (NSString *)formatDateTimeWithFormatString:(NSString *)formatString Date:(NSDate *)date {
    [dateFormatter setDateFormat:formatString];
	return [dateFormatter stringFromDate:date];
}

/**
 파라미터 date로부터 formatString에 맞는 날짜를 문자열로 리턴.\n
 자세한 날짜 포멧은 Apple API 참조
 @param formatString 날짜 포멧
 @param date 날짜 객체
 @param localeName 로케일 명
 @return 날짜 문자열 리턴
 */
- (NSString *)formatDateTimeWithFormatString:(NSString *)formatString Date:(NSDate *)date LocaleName:(NSString *)localeName {
    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:localeName];

    NSLocale *oldlocale = [dateFormatter locale];
	[dateFormatter setLocale:locale];
    
    [dateFormatter setDateFormat:formatString];
	NSString *dateValue = [dateFormatter stringFromDate:date];   
    [dateFormatter setLocale:oldlocale];
    
    return dateValue;
}

/**
 파라미터 dateString을 NSDate로 변환하여 리턴한다. dateString은 yyyy-MM-dd Fomat과 동일해야야 한다.
 @param dateString 문자열 날짜
 @return dateString이 NSDate로 변환된 객체 리턴
*/
- (NSDate *)getDateFromString:(NSString *)dateString {
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    return [dateFormatter dateFromString:dateString];
}

/**
 파라미터 dateString을 NSDate로 변환하여 리턴한다. dateString은 파라미터 formatString의 format과 동일해야야 한다.
 @param dateString 문자열 날짜
 @param formatString 날짜 Format String
 @return dateString이 NSDate로 변환된 객체 리턴
*/
- (NSDate *)getDateFromString:(NSString *)dateString withFormatString:(NSString *)formatString {
    [dateFormatter setDateFormat:formatString];
    return [dateFormatter dateFromString:dateString];
}

/**
 파라미터 date의 해당 월의 마지막 일자를 리턴한다.
 @param month 날짜 객체
 @return 해당 월의 마지막 일자가 리턴됨
*/
- (int)dayOfMonth:(NSDate *)month {
    NSRange days = [gregorian rangeOfUnit:NSDayCalendarUnit  
                                   inUnit:NSMonthCalendarUnit  
                                  forDate:month];
    return days.length;
}

/**
 파라미터 date의 해당 월이 몇주가 있는지 리턴.
 @param date 날짜 객체
 @return 해당 월의 주 차수 리턴
 */
- (int)weekOfMonth:(NSDate *)date {
    [dateFormatter setDateFormat:@"W"];
	return [[dateFormatter stringFromDate:date] intValue];
}

/**
 파라미터 date의 요일 정보 리턴
 @param date 날짜 객체
 @return date의 요일 인덱스 리턴\n
			0: 일요일\n
			1: 월요일\n
			2: 화요일\n
			3: 수요일\n
			4: 목요일\n
			5: 금요일\n
			6: 토요일
 
 */
- (int)dayOfWeek:(NSDate *)date {
    [gregorian setFirstWeekday:0];
    
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit;
    NSDateComponents *todaysDate = [gregorian components:unitFlags fromDate:date];

    return todaysDate.weekday;
}

/**
 파라미터 date에 해당하는 주의 토요일의 NSDate 객체를 리턴
 @param date 날짜 객체
 @return date에 해당하는 주의 토요일 NSDate 객체를 리턴
 */
- (NSDate *)dayOfWeekSaturdayDate:(NSDate *)date {
    [gregorian setFirstWeekday:0];
    
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit;
    NSDateComponents *todaysDate = [gregorian components:unitFlags fromDate:date];
    
    int dayOfWeek = todaysDate.weekday;
    int cnt = 7 - dayOfWeek;
    if (cnt > 0) 
        return [self incDay:date increment:cnt];
    else 
        return date;
}

/**
 파라미터 date에 해당하는 주의 월요일의 NSDate 객체를 리턴
 @param date 날짜 객체
 @return date에 해당하는 주의 월요일 NSDate 객체를 리턴
*/
- (NSDate *)dayofWeekMondayDate:(NSDate *)date {
    [gregorian setFirstWeekday:0];
    
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit;
    NSDateComponents *todaysDate = [gregorian components:unitFlags fromDate:date];
    
    int dayOfWeek = todaysDate.weekday - 2;
    if (dayOfWeek > 0) 
        return [self decDay:date decrement:dayOfWeek];
    else 
        return date;
}

/**
 파라미터 date에 해당하는 주의 일요일의 NSDate 객체를 리턴
 @param date 날짜 객체
 @return date에 해당하는 주의 일요일 NSDate 객체를 리턴
*/
- (NSDate *)dayOfWeekSundayDate:(NSDate *)date {
    [gregorian setFirstWeekday:0];
    
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit;
    NSDateComponents *todaysDate = [gregorian components:unitFlags fromDate:date];
    
    int dayOfWeek = todaysDate.weekday - 1;
    if (dayOfWeek > 0) 
        return [self decDay:date decrement:dayOfWeek];
    else 
        return date;
}

/**
 요일명 리스트 배열을 리턴
 */
- (NSArray *)getWeekDaySymbols {
    return dateFormatter.weekdaySymbols;
}

/**
 date가 from과 to 사이에 있는지 판단한다. 리턴값이 YES이면 date가 from과 To사이에 존재하고 NO이면 존재하지 않는다.
 @param date 날짜객체
 @param from 시작날짜 객체
 @param to 끝날짜 객체
 @returm 리턴값이 YES이면 date가 from과 to 사이에 존재하고 NO이면 존재하지 않는다.
 */
- (BOOL)betweenDate:(NSDate *)date From:(NSDate *)from To:(NSDate *)to {
    BOOL between = NO;
        
    if (([date compare:from] == NSOrderedDescending) && ([date compare:to] == NSOrderedAscending)) 
        between = YES;
    else if ([date isEqualToDate:from] || [date isEqualToDate:to])
        between = YES;
    
    return between;
}

/**
 날짜를 반올림한다.
 @param date 날짜객체
 @param rangeUnit
 @returm 반올림된 날짜객체 리턴
 */
- (NSDate *)roundMinuteWithDate:(NSDate *)date rangeUnit:(int)rangeUnit {
    if (rangeUnit == 0) 
        return date;

    int minute = [self getMinuteFromDate:date];
    int mod = minute % rangeUnit;

    return [self incMinutes:date increment:rangeUnit - mod];
}

/**
 파라미터 fromDate부터 toDate까지 날수를 리턴한다.
 @param fromDate 시작날짜 객체
 @param toDate 끝날짜 객체
 @returm fromDate부터 toDate까지 날수를 리턴.
 */
- (int)betweenDayFromDate:(NSDate *)fromDate TodDate:(NSDate *)toDate {
	unsigned int unitFlags = NSDayCalendarUnit;
	NSDateComponents *components = [gregorian components:unitFlags
												fromDate:fromDate
												  toDate:toDate options:0];
	return [components day];
}

- (int)betweenSecondFromDate:(NSDate *)fromDate TodDate:(NSDate *)toDate {
	unsigned int unitFlags = NSSecondCalendarUnit;
	NSDateComponents *components = [gregorian components:unitFlags
												fromDate:fromDate
												  toDate:toDate options:0];
    
    NSLog(@"betweenSecond = %d", [components second]);
	return [components second];
}


/**
 파라미터 date객체로 부터 년도 시간을 리턴한다. 시간은 12시간 체계 임
 @param date 날짜 객체
 @return 시간
 */
- (int)getHour12FromDate:(NSDate *)date {
    [dateFormatter setDateFormat:@"hh"];
    return [[dateFormatter stringFromDate:date] intValue];
}

/**
 파라미터 date객체로 부터 AM/PM 을 리턴한다. date는 24시간 체계 임
 @param date 날짜 객체
 @return 시간
 */
- (NSString *)getAPMFromDate:(NSDate *)date {
    if ([self getHourFromDate:date] < 12) {
        return @"AM";
    } else {
        return @"PM";
    }
}

/**
 파라미터 date객체로 부터 AM/PM 을 리턴한다. date는 24시간 체계 임
 @param date 날짜 객체
 @return 시간
 */
- (NSString *)getAPMFromDateKor:(NSDate *)date {
    if ([self getHourFromDate:date] < 12) {
        return @"오전";
    } else {
        return @"오후";
    }
}

/**
 파라미터 시/분으로 날짜 객체 반환한다.
 @param hour 시간 (24시간 기준)
 @param min 분
 @return 시간
 */
- (NSDate *)getTimeFronInt:(int)hour min:(int)min {
    
    NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
    NSDateComponents *dateComps = [[NSDateComponents alloc] init];

    [dateComps setHour:hour];
    [dateComps setMinute:min];
    
    return [calendar dateFromComponents:dateComps];
}

/**
 파라미터 03:15 로부터 날짜 객체 반환한다.
 @param timeString 시간 (03:15)
 @return 시간
 */
- (NSDate *)getTimeFromString:(NSString *)timeString {
    
    NSArray *timeArrray = [timeString componentsSeparatedByString:@":"];
    if ([timeArrray count] > 1) {
        return [self getTimeFronInt:[[timeArrray objectAtIndex:0] intValue] 
                                min:[[timeArrray objectAtIndex:1] intValue]];
    }
    return nil;
}

/**
 파라미터 시간(12시간 기준) 문자열 반환한다.
 @param date 날짜 객체
 @return 시간
 */
- (NSString *)getTime12String:(NSDate *)date {
    [dateFormatter setDateFormat:@"hh:mm"];
    return [dateFormatter stringFromDate:date];
}

/**
 파라미터 두 날짜로 부터 날짜 차이를 반환한다.
 @param fromDay 날짜 객체
 @param toDay 날짜 객체
 @return 날짜차이(일)
 */
- (int)getBetweenDays:(NSDate *)fromDay toDate:(NSDate *)toDay
{
    NSDateComponents *dateComps;
    fromDay = [self getDateFromString:[self formatDateTimeWithFormatString:@"yyyy-MM-dd" Date:fromDay]];
    toDay = [self getDateFromString:[self formatDateTimeWithFormatString:@"yyyy-MM-dd" Date:toDay]];    
    dateComps = [[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:fromDay toDate:toDay options:0];
    return [dateComps day];
}

@end
